package 多线程;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.function.IntConsumer;

/**
 假设有这么一个类：

 class ZeroEvenOdd {
   public ZeroEvenOdd(int n) { ... }      // 构造函数
 public void zero(printNumber) { ... }  // 仅打印出 0
 public void even(printNumber) { ... }  // 仅打印出 偶数
 public void odd(printNumber) { ... }   // 仅打印出 奇数
 }
 相同的一个 ZeroEvenOdd 类实例将会传递给三个不同的线程：
 线程 A 将调用 zero()，它只输出 0 。
 线程 B 将调用 even()，它只输出偶数。
 线程 C 将调用 odd()，它只输出奇数。
 每个线程都有一个 printNumber 方法来输出一个整数。请修改给出的代码以输出整数序列 010203040506... ，其中序列的长度必须为 2n。
 示例 1：
 输入：n = 2
 输出："0102"
 说明：三条线程异步执行，其中一个调用 zero()，另一个线程调用 even()，最后一个线程调用odd()。正确的输出为 "0102"。
 示例 2：
 输入：n = 5
 输出："0102030405"
 */
public class _1116打印零与奇偶数 {

    private int n;

    private Lock lock = new ReentrantLock();
    private Condition c1 =  lock.newCondition();
    private Condition c2 =  lock.newCondition();
    private Condition c3 =  lock.newCondition();
    private int state = 0;
    private int current = 1;
    public _1116打印零与奇偶数(int n) {
        this.n = n;
    }

    // printNumber.accept(x) outputs "x", where x is an integer.
    public void zero(IntConsumer printNumber) throws InterruptedException {

        lock.lock();
        try{
            while( current <= n){
                if( state!=0 ){
                    c1.await();
                }
                printNumber.accept(0);
                if( (current & 1)==0 ){
                    state = 2;
                    c2.signal();
                }else {
                    state = 1;
                    c3.signal();
                }
                c1.await();
            }
            c2.signal();
            c3.signal();
        } finally {
            lock.unlock();
        }




    }

    public void even(IntConsumer printNumber) throws InterruptedException {
        lock.lock();
        try{
            while( current<= n){
                if (state != 2) {
                    c2.await();
                } else {
                    printNumber.accept(current++);
                    state = 0;
                    c1.signal();
                }
            }

        } finally {
            lock.unlock();
        }
    }

    public void odd(IntConsumer printNumber) throws InterruptedException {
        lock.lock();
        try{
            while( current<= n){
                if (state != 1) {
                    c3.await();
                } else {
                    printNumber.accept(current++);
                    state = 0;
                    c1.signal();
                }
            }
        } finally {
            lock.unlock();
        }
    }
}
